﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using XRoute.DataExchange;

namespace XRoute.Server.Services.Dex
{
    class DataExchangeContainer : IDisposable
    {
        ///////////////////////////////////////////////////////////////////////

        readonly Host _host;
        readonly IDataExchangeContext _context;
        readonly ConcurrentDictionary<string, DataExchangeSession> _sessions =
            new ConcurrentDictionary<string, DataExchangeSession>();


        ///////////////////////////////////////////////////////////////////////

        public DataExchangeContainer(IDataExchangeContext context)
        : this(context, null)
        {
            Contract.Requires(context != null);
        }

        public static DataExchangeContainer Current
        {
            get { return ((Host)OperationContext.Current.Host).Container; }
        }

        public IDataExchangeContext Context
        {
            get { return _context; }
        }

        public DataExchangeSession OpenSession(IDataExchangeServiceCallback callback, string clientMoniker)
        {
            var session = DataExchangeSession.CreateNew(callback, clientMoniker);

            return _sessions.TryAdd(session.Sid, session)
                   ? session
                   : null;
        }

        public DataExchangeSession GetSession(string sid)
        {
            DataExchangeSession session;

            return _sessions.TryGetValue(sid, out session)
                   ? session
                   : null;
        }

        public void CloseSession(string sid)
        {
            DataExchangeSession dummy;

            _sessions.TryRemove(sid, out dummy);
        }

        public void Dispose()
        {
            _host.Close();
        }

        internal static DataExchangeContainer CreateLocal(IDataExchangeContext context)
        {
            var endpoint = new ServiceEndpoint(
                ContractDescription.GetContract(typeof(IDataExchangeService), typeof(DataExchangeService)),
                new NetNamedPipeBinding(),
                new EndpointAddress("net.pipe://localhost/XRoute/DataExchange/"));

            return new DataExchangeContainer(context, endpoint);
        }

        internal static DuplexChannelFactory<IDataExchangeService> CreateLocalChannelFactory(IDataExchangeServiceCallback callback)
        {
            return new DuplexChannelFactory<IDataExchangeService>(
                callback,
                new NetNamedPipeBinding(),
                new EndpointAddress("net.pipe://localhost/XRoute/DataExchange/"));
        }


        ///////////////////////////////////////////////////////////////////////

        DataExchangeContainer(IDataExchangeContext context, ServiceEndpoint localEndpoint)
        {
            _context = context;
            _host = new Host(this);

            if (localEndpoint != null)
                _host.AddServiceEndpoint(localEndpoint);

            _host.Open();
        }

        class Host : ServiceHost
        {
            internal readonly DataExchangeContainer Container;

            internal Host(DataExchangeContainer container)
            : base(typeof(DataExchangeService))
            {
                Container = container;
            }
        }
    }
}
